﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Controls;

namespace Red.Toolkit.Profiler.Logic
{
    /// <summary>
    /// View for a profiler trace data of a specific type (e.g. I/O, job).
    /// Data view contains:
    /// * groups (threads) containing events
    /// * graphs (calculated based on events and counters)
    /// </summary>
    public abstract class ProfilerDataView
    {
        private bool visible;

        protected string name;
        protected string filePath;
        protected ProfilerData profilerData;
        protected ProfilerViewStyle style;
        protected List<Group> groups;
        protected List<Graph> graphs;
        protected SortedDictionary<double, Region> regions;
        protected SortedDictionary<double, Event> allEvents;
        protected HashSet<double> timeSlots;
        private ProfilerTraceInstance trace;

        // HACK for TreeView
        protected List<TreeViewItem> subItems;

        public ProfilerDataView( string name, string path, ProfilerData data, ProfilerTraceInstance trace )
        {
            this.name = name;
            this.trace = trace;
            filePath = path;
            profilerData = data;
            visible = true;

            style = new ProfilerViewStyle();
            groups = new List<Group>();
            graphs = new List<Graph>();
            regions = new SortedDictionary<double, Region>();
            allEvents = new SortedDictionary<double, Event>();
            timeSlots = new HashSet<double>();

            // HACK
            subItems = new List<TreeViewItem>();

            TreeViewItem groupSubItem = new TreeViewItem();
            groupSubItem.Header = "Groups";
            groupSubItem.ItemsSource = groups;
            groupSubItem.IsExpanded = true;
            subItems.Add( groupSubItem );

            TreeViewItem graphSubItem = new TreeViewItem();
            graphSubItem.Header = "Graphs";
            graphSubItem.ItemsSource = graphs;
            groupSubItem.IsExpanded = true;
            subItems.Add( graphSubItem );
        }

        public ProfilerTraceInstance Trace { get { return trace; } }
        public string Name { get { return name; } }
        public bool Visible { get { return visible; } set { visible = value; } }
        public string FilePath { get { return filePath; } }
        public string FileName { get { return Path.GetFileName( filePath ); } }
        public ProfilerViewStyle Style { get { return style; } }
        public List<Group> Groups { get { return groups; } }
        public List<Graph> Graphs { get { return graphs; } }
        public SortedDictionary<double, Region> Regions { get { return regions; } }
        public List<TreeViewItem> SubItems { get { return subItems; } } // HACK
        public double Length { get { return profilerData.Length; } }

        public string Details
        {
            get
            {
                return Utils.FormatValue( profilerData.MinTime, ValueType.Time ) + " - " +
                    Utils.FormatValue( profilerData.MaxTime, ValueType.Time );
            }
        }

        protected Group AddGroup( string name, bool stackStructure )
        {
            Group group = new Group( name, stackStructure );
            groups.Add( group );
            return group;
        }

        protected Region AddRegion( ulong eventTime, string name, double start, double end, int style )
        {
            Region reg = new Region( name, start, end, style );
            regions.Add( eventTime, reg );
            return reg;
        }

        protected void AddEvent( Event e, Group targetGroup )
        {
            if ( e.Evt.StartTime == e.Evt.EndTime )
            {
                Debug.Write( "Warning: Event '" + e.GetCaption() + "' has length equal to zero, start=" + e.Evt.StartTime + "\n" );
                return;
            }

            if ( timeSlots.Contains( e.Evt.StartTime ) )
            {
                Debug.Write( "Warning: Overlapping time slot found event ('" + e.GetCaption() + "', start=" + e.Evt.StartTime + ")\n" );
                return;
            }

            if ( timeSlots.Contains( e.Evt.EndTime ) )
            {
                Debug.Write( "Warning: Overlapping time slot found event ('" + e.GetCaption() + "', end=" + e.Evt.EndTime + ")\n" );
                return;
            }

            targetGroup.AddEvent( e );
            allEvents.Add( e.Evt.StartTime, e );
            timeSlots.Add( e.Evt.StartTime );
            timeSlots.Add( e.Evt.EndTime );
        }

        protected void AddLink( Event from, Event to )
        {

        }

        public bool Prepare()
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            if ( !AnalyzeRawData() )
                return false;
            stopwatch.Stop();
            Debug.Write( "Data analyzing: " + stopwatch.Elapsed + " sec\n" );

            return true;
        }

        protected abstract bool AnalyzeRawData();
        public abstract string GetDescription( IList<Event> events );
        public abstract string[] GetStatGraphsNames();
        public abstract string[] GetBlockHitDataNames();
    }
}
